#+++++++++++++++++++++++++++++++++configure++++++++++++++++++++++++++++++++++++++++
# OS=Windows,Linux,Android
# ARCH=x86,x86_64,arm,aarch64
# CC  = $(CROSS_COMPILE)gcc
# CXX = $(CROSS_COMPILE)g++
# CPPFLAGS += $(addprefix -D, $(DEFINES))
# CPPFLAGS += $(addprefix -I, $(SRCDIRS))
# CPPFLAGS += $(addprefix -I, $(INCDIRS))
# LDFLAGS  += $(addprefix -L, $(LIBDIRS))
# LDFLAGS  += $(addprefix -l, $(LIBS))
#
# Usage:
# make all \
# TARGET=libxx \
# TARGET_TYPE=SHARED \
# CROSS_COMPILE=arm-linux-androideabi- \
# SRCDIRS="src/base src/event" \
# INCDIRS="src/utils" \
# SRCS="src/utils/hmain.cpp src/utils/iniparser.cpp" \
# DEFINES=USE_OPENCV \
# LIBS="opencv_core opencv_highgui"
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-include config.mk

# VARIABLES
TARGET ?= test
# BUILD_TYPE=DEBUG,RELEASE
BUILD_TYPE ?= RELEASE
# TARGET_TYPE=EXECUTABLE,SHARED,STATIC,SHARED|STATIC
TARGET_TYPE ?= EXECUTABLE

# COMMANDS
ifdef CROSS_COMPILE
CC 	= $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
CPP = $(CC) -E
AS 	= $(CROSS_COMPILE)as
LD	= $(CROSS_COMPILE)ld
AR	= $(CROSS_COMPILE)ar
NM	= $(CROSS_COMPILE)nm
STRIP 	= $(CROSS_COMPILE)strip
endif

MKDIR = -mkdir -p 2>/dev/null
CP = -cp -r 2>/dev/null
RM = -rm -r 2>/dev/null

# PLATFORM: OS, ARCH
CC_VERSION=$(shell $(CC) --version 2>&1 | head -n 1)
TARGET_PLATFORM=$(shell $(CC) -v 2>&1 | grep Target | sed 's/Target: //')
ifneq ($(findstring mingw, $(TARGET_PLATFORM)), )
	OS=Windows
endif
ifneq ($(findstring android, $(TARGET_PLATFORM)), )
	OS=Android
endif
ifneq ($(findstring darwin, $(TARGET_PLATFORM)), )
	OS=Darwin
endif
ifndef OS
	OS=Linux
endif

ifndef ARCH
ARCH=$(shell echo $(TARGET_PLATFORM) | awk -F'-' '{print $$1}')
endif

# CFLAGS, CXXFLAGS, ARFLAGS
ifeq ($(BUILD_TYPE), DEBUG)
	DEFAULT_CFLAGS = -g -Wall -O0
else
	DEFAULT_CFLAGS += -O2
endif

CFLAGS ?= $(DEFAULT_CFLAGS)
CXXFLAGS ?= $(DEFAULT_CFLAGS)

ifneq ($(OS), Windows)
ifeq ($(findstring -fPIC, $(CFLAGS)), )
override CFLAGS += -fPIC
endif
ifeq ($(findstring -fPIC, $(CXXFLAGS)), )
override CXXFLAGS += -fPIC
endif
endif

ifeq ($(findstring -std, $(CFLAGS)), )
override CFLAGS += -std=c99
endif

ifeq ($(findstring -std, $(CXXFLAGS)), )
override CXXFLAGS += -std=c++11
endif

ARFLAGS ?= cr

# DIRS
ifeq ($(OS), Linux)
	PREFIX ?= /usr/local
else
	PREFIX ?= install
endif

INCDIR = include
LIBDIR = lib
SRCDIR = src
BINDIR = bin
DEPDIR = 3rd
CONFDIR = etc
DISTDIR = dist
DOCDIR  = docs

SRCDIRS += $(shell find $(SRCDIR) -type d)
override INCDIRS += $(INCDIR) $(DEPDIR) $(DEPDIR)/include
override LIBDIRS += $(LIBDIR) $(DEPDIR)/lib $(DEPDIR)/lib/$(TARGET_PLATFORM)

# CPPFLAGS
ifeq ($(OS), Windows)
	CPPFLAGS += -D_WIN32_WINNT=0x600
ifeq ($(TARGET_TYPE), SHARED)
	CPPFLAGS += -DDLL_EXPORTS
endif
endif

ifeq ($(BUILD_TYPE), DEBUG)
	CPPFLAGS += -DDEBUG
else
	CPPFLAGS += -DNDEBUG
endif

ifeq ($(ENABLE_IPV6), yes)
	CPPFLAGS += -DENABLE_IPV6
endif

ifeq ($(ENABLE_UDS), yes)
	CPPFLAGS += -DENABLE_UDS
endif

ifeq ($(USE_MULTIMAP), yes)
	CPPFLAGS += -DUSE_MULTIMAP
endif

CPPFLAGS += $(addprefix -D, $(DEFINES))
CPPFLAGS += $(addprefix -I, $(INCDIRS))
CPPFLAGS += $(addprefix -I, $(SRCDIRS))

# LDFLAGS
ifeq ($(OS), Windows)
	LDFLAGS += -static-libgcc -static-libstdc++
endif

ifeq ($(WITH_CURL), yes)
	CPPFLAGS += -DWITH_CURL
	LDFLAGS += -lcurl
ifeq ($(OS), Windows)
	LDFLAGS += -lwldap32 -ladvapi32 -lcrypt32
endif
endif

ifeq ($(WITH_NGHTTP2), yes)
	CPPFLAGS += -DWITH_NGHTTP2
	LDFLAGS += -lnghttp2
endif

ifeq ($(WITH_OPENSSL), yes)
	CPPFLAGS += -DWITH_OPENSSL
	LDFLAGS += -lssl -lcrypto
else
ifeq ($(WITH_MBEDTLS), yes)
	CPPFLAGS += -DWITH_MBEDTLS
	LDFLAGS += -lmbedtls -lmbedx509 -lmbedcrypto
endif
endif

LDFLAGS += $(addprefix -L, $(LIBDIRS))
LDFLAGS += $(addprefix -l, $(LIBS))

ifeq ($(OS), Windows)
	LDFLAGS += -lwinmm -liphlpapi -lws2_32
ifeq ($(ENABLE_WINDUMP), yes)
	CPPFLAGS += -DENABLE_WINDUMP
	LDFLAGS += -ldbghelp
endif
	LDFLAGS += -Wl,-Bstatic -lstdc++ -lpthread -lm
else
ifeq ($(OS), Android)
	LDFLAGS += -lstdc++ -lm -llog -ldl
else
	LDFLAGS += -lstdc++ -lpthread -lm -ldl
ifneq ($(findstring gcc, $(CC_VERSION)), )
	LDFLAGS += -lrt # for clock_gettime, clang not -lrt
endif
endif
endif

ALL_SRCS += $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c $(dir)/*.cc $(dir)/*.cpp))
ifeq ($(ALL_SRCS), )
	ALL_SRCS = $(wildcard *.c *.cc *.cpp)
endif
override SRCS += $(filter-out %_test.c %_test.cc %_test.cpp, $(ALL_SRCS))
# OBJS += $(patsubst %.c, %.o, $(SRCS))
# OBJS += $(patsubst %.cc, %.o, $(SRCS))
# OBJS += $(patsubst %.cpp, %.o, $(SRCS))
OBJS := $(addsuffix .o, $(basename $(SRCS)))

INSTALLED_INCS=$(addprefix $(PREFIX)/$(INCDIR)/, $(shell ls $(INCDIR)))
INSTALLED_LIBS=$(addprefix $(PREFIX)/$(LIBDIR)/, $(shell ls $(LIBDIR)))
INSTALLED_BINS=$(addprefix $(PREFIX)/$(BINDIR)/, $(shell ls $(BINDIR)))

# info
$(info $(CC_VERSION))

$(info OS   = $(OS))
$(info ARCH = $(ARCH))
$(info MAKE = $(MAKE))
$(info CC   = $(CC))
$(info CXX  = $(CXX))

$(info CFLAGS   = $(CFLAGS))
$(info CXXFLAGS = $(CXXFLAGS))
$(info CPPFLAGS = $(CPPFLAGS))
$(info LDFLAGS  = $(LDFLAGS))

$(info TARGET           = $(TARGET))
$(info TARGET_TYPE      = $(TARGET_TYPE))
$(info TARGET_PLATFORM  = $(TARGET_PLATFORM))
$(info BUILD_TYPE       = $(BUILD_TYPE))

$(info SRCS=$(SRCS))
$(info OBJS=$(OBJS))

# $(info INSTALLED_INCS=$(INSTALLED_INCS))
# $(info INSTALLED_LIBS=$(INSTALLED_LIBS))
# $(info INSTALLED_BINS=$(INSTALLED_BINS))

default: all

all: prepare $(TARGET)

prepare:
	$(MKDIR) $(BINDIR) $(LIBDIR)

$(TARGET): $(OBJS)
ifneq ($(findstring SHARED, $(TARGET_TYPE)), )
ifeq ($(OS), Windows)
	$(CC) -shared $^ -o $(LIBDIR)/$@.dll $(LDFLAGS) -Wl,--output-def,$(LIBDIR)/$(@).def
else
ifeq ($(OS), Darwin)
	$(CC) -dynamiclib -install_name @rpath/$@.dylib $^ -o $(LIBDIR)/$@.dylib $(LDFLAGS)
else
	$(CC) -shared $^ -o $(LIBDIR)/$@.so $(LDFLAGS)
endif
endif
endif

ifneq ($(findstring STATIC, $(TARGET_TYPE)), )
	$(AR) $(ARFLAGS) $(LIBDIR)/$@.a $^
endif

ifneq ($(findstring EXECUTABLE, $(TARGET_TYPE)), )
ifeq ($(OS), Windows)
	$(CC) $^ -o $(BINDIR)/$@.exe $(LDFLAGS)
else
	$(CC) $^ -o $(BINDIR)/$@ $(LDFLAGS)
endif
endif

clean:
	$(RM) $(OBJS)
	#$(RM) $(LIBDIR)
	#$(RM) $(BINDIR)

install:
	$(CP) $(INCDIR)/* $(PREFIX)/$(INCDIR)/
	$(CP) $(LIBDIR)/* $(PREFIX)/$(LIBDIR)/
	$(CP) $(BINDIR)/* $(PREFIX)/$(BINDIR)/

uninstall:
	$(RM) $(INSTALLED_INCS)
	$(RM) $(INSTALLED_LIBS)
	$(RM) $(INSTALLED_BINS)

dist:
	$(MKDIR) $(DISTDIR)
	$(CP) $(INCDIR) $(LIBDIR) $(BINDIR) $(CONFDIR) $(DOCDIR) $(DISTDIR)

undist:
	$(RM) $(DISTDIR)

.PHONY: default all prepare clean install uninstall dist undist
